/** @file

Copyright (c) 2006-2023, Kunlun BIOS, Kunlun Technology (Beijing) Co., Ltd.. All
Rights Reserved.

You may not reproduce, distribute, publish, display, perform, modify, adapt,
transmit, broadcast, present, recite, release, license or otherwise exploit
any part of this publication in any form, by any means, without the prior
written permission of Kunlun Technology (Beijing) Co., Ltd..

Module Name:


Abstract:


Revision History:

**/

#include "Main.h"
#include <Library/BaseMemoryLib.h>
#include <Library/DxeServicesTableLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiRuntimeServicesTableLib.h>
#include <Guid/MdeModuleHii.h>
#include <Guid/HiiPlatformSetupFormset.h>
#include <Protocol/HiiString.h>
//modify-klk-lyang-P000A-start//
//#include <Version.h>
#include <BiosIdLib.h>
//modify-klk-lyang-P000A-end//
//add-fanchen-start
#include <Library/ArmSmcLib.h>
//add-fanchen-end
//[gliu-0009]
#include <Library/HobLib.h>
#include <Library/FlashLib.h>
#include <Library/IoLib.h>
//[gliu-0009]

//#include <Library/PrintLib.h>
#define PRINTABLE_LANGUAGE_NAME_STRING_ID     0x0001
#define FRONT_PAGE_KEY_LANGUAGE               0x1002

EFI_GUID   mFormMainGuid                          = FORMSET_ID_GUID_MAIN;
STATIC EFI_CALLBACK_INFO                          *mMainCallBackInfo    = NULL;
CHAR8                                             *gLanguageString      = NULL;
EFI_STRING_ID                                     *gLanguageToken       = NULL;
UINT8                                             gCurrentLanguageIndex;
EFI_EVENT                                         mSwitchLanEvent = NULL;
//add-klk-lyang-P000A-start//
//add-klk-lyang-P000A-end//
//add-fanchen-start
SYSTEM_SETUP_CONFIGURATION       mSetupConfiguration;
//add-fanchen-end
extern EFI_SMBIOS_HANDLE               gSmbiosHandle;
extern EFI_SMBIOS_TYPE                 gSmbiosType;

extern EFI_SMBIOS_PROTOCOL      *gSmbiosProtocol;

/**
  Get next language from language code list (with separator ';').

  If LangCode is NULL, then ASSERT.
  If Lang is NULL, then ASSERT.

  @param  LangCode    On input: point to first language in the list. On
                                 output: point to next language in the list, or
                                 NULL if no more language in the list.
  @param  Lang           The first language in the list.

**/
VOID
GetNextLanguage (
  IN OUT CHAR8      **LangCode,
  OUT CHAR8         *Lang
  )
{
  UINTN  Index;
  CHAR8  *StringPtr;

  ASSERT (LangCode != NULL);
  ASSERT (*LangCode != NULL);
  ASSERT (Lang != NULL);

  Index = 0;
  StringPtr = *LangCode;
  while (StringPtr[Index] != 0 && StringPtr[Index] != ';') {
    Index++;
  }

  CopyMem (Lang, StringPtr, Index);
  Lang[Index] = 0;

  if (StringPtr[Index] == ';') {
    Index++;
  }
  *LangCode = StringPtr + Index;
}

/**
  Brief description of EfiSignalEventSwitchLan.

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EfiSignalEventSwitchLan (
  VOID
  )
{
  EFI_STATUS           Status;

  Status = EFI_SUCCESS;
  if (mSwitchLanEvent == NULL) {
    Status = gBS->CreateEventEx (
                    EVT_NOTIFY_SIGNAL,
                    TPL_CALLBACK,
                    EfiEventEmptyFunction,
                    NULL,
                    &gEfiEventSwtichLanGuid,
                    &mSwitchLanEvent
                    );
  }
  if (!EFI_ERROR (Status)) {
    Status = gBS->SignalEvent (mSwitchLanEvent);
  }
  return Status;
}

/**
  This function processes the language changes in configuration.

  @param Value           A pointer to the data being sent to the original exporting driver.


  @retval  TRUE          The callback successfully handled the action.
  @retval  FALSE         The callback not supported in this handler.

**/
EFI_STATUS
LanguageChangeHandler (
  IN  EFI_IFR_TYPE_VALUE                     *Value
  )
{
  CHAR8                         *LangCode;
  CHAR8                         *Lang;
  UINTN                         Index;
  EFI_STATUS                    Status;

  //
  // Allocate working buffer for RFC 4646 language in supported LanguageString.
  //
  Lang = AllocatePool (AsciiStrSize (gLanguageString));
  ASSERT (Lang != NULL);

  Index = 0;
  LangCode = gLanguageString;
  while (*LangCode != 0) {
    GetNextLanguage (&LangCode, Lang);

    if (Index == Value->u8) {
      gCurrentLanguageIndex = Value->u8;
      break;
    }
    Index++;
  }
  if (Index == Value->u8) {
    UINTN       LangSize;
    CHAR8       LangData[100];

    gRT->GetVariable (L"PlatformLang", &gEfiGlobalVariableGuid, NULL, &LangSize, LangData);
    if (!CompareMem(LangData, Lang, AsciiStrSize (Lang))) {
      return EFI_SUCCESS;
    }
    if (CheckSetupHiiDataManager()) {
      gSetupDataManagment->LayoutIsChanged = TRUE;
      gSetupDataManagment->Firstin = TRUE;
      gSetupDataManagment->RepaintFrameLine = FALSE;
      //DEBUG((EFI_D_ERROR, "lenovo: In Main.c, line %d.gSetupDataManagment->RepaintFrameLine %d \n", __LINE__,gSetupDataManagment->RepaintFrameLine));
      //DEBUG ((EFI_D_ERROR, "Set language , need layout updated \n"));
    }

    Status = gRT->SetVariable (
                    L"PlatformLang",
                    &gEfiGlobalVariableGuid,
                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
                    AsciiStrSize (Lang),
                    Lang
                    );
    if (EFI_ERROR (Status)) {
      FreePool (Lang);
      return EFI_DEVICE_ERROR;
    }
//add-klk-lyang-P000A-start//
    EfiSignalEventSwitchLan();
//add-klk-lyang-P000A-end//
  } else {
    ASSERT (FALSE);
  }
  FreePool (Lang);
  return EFI_SUCCESS;
}

/**
  Create Select language menu in the front page with oneof opcode.

  @param[in]    HiiHandle           The hii handle for the Uiapp driver.

**/
VOID
UiCreateLanguageMenu (
  IN EFI_HII_HANDLE                HiiHandle
  )
{
  EFI_STATUS                  Status;
  VOID                        *StartOpCodeHandle;
  VOID                        *EndOpCodeHandle;
  VOID                        *OptionsOpCodeHandle;
  EFI_IFR_GUID_LABEL          *StartLabel;
  EFI_IFR_GUID_LABEL          *EndLabel;
  CHAR8                       *CurrentLang;
  UINTN                       OptionCount;
  CHAR8                       *LangCode;
  CHAR8                       *Lang;
  EFI_HII_STRING_PROTOCOL     *HiiString;
  UINTN                       StringSize;
  CHAR16                      *StringBuffer;
  UINT8                       Flag;

  Status = EFI_NOT_FOUND;
  Lang         = NULL;
  StringBuffer = NULL;
  Flag = 0;

  //
  // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
  //
  StartOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (StartOpCodeHandle != NULL);

  EndOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (EndOpCodeHandle != NULL);

  OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
  ASSERT (OptionsOpCodeHandle != NULL);
  //
  // Create Hii Extend Label OpCode as the start opcode
  //
  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
  StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
  StartLabel->Number     = LABEL_SELECT_LANGUAGE;

  //
  // Create Hii Extend Label OpCode as the end opcode
  //
  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
  EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
  EndLabel->Number     = LABEL_SELECT_LANGUAGE_END;

  //
  // Collect the languages from what our current Language support is based on our VFR
  //

  GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
  //
  // Get Support language list from variable.
  //
  if (gLanguageString == NULL) {
    GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL);
    if (gLanguageString == NULL) {
      gLanguageString = AllocateCopyPool (
                          AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
                          (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
                          );
    ASSERT (gLanguageString != NULL);
    }
  }
//add-klk-lyang-P000A-start//
  if (gLanguageToken != NULL) {
    FreePool(gLanguageToken);
    gLanguageToken = NULL;
  }
//add-klk-lyang-P000A-end//

  if (gLanguageToken == NULL) {
    //
    // Count the language list number.
    //
    LangCode      = gLanguageString;
    Lang          = AllocatePool (AsciiStrSize (gLanguageString));
    ASSERT (Lang != NULL);
    OptionCount = 0;
    while (*LangCode != 0) {
      GetNextLanguage (&LangCode, Lang);
      OptionCount ++;
    }
    //
    // Allocate extra 1 as the end tag.
    //
    gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
    ASSERT (gLanguageToken != NULL);

    Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
    ASSERT_EFI_ERROR (Status);

    LangCode     = gLanguageString;
    OptionCount  = 0;
    while (*LangCode != 0) {
      GetNextLanguage (&LangCode, Lang);
      StringSize = 0;
      Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
      if (Status == EFI_BUFFER_TOO_SMALL) {
      StringBuffer = AllocateZeroPool (StringSize);
      ASSERT (StringBuffer != NULL);
      Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
      ASSERT_EFI_ERROR (Status);
      }
      if (EFI_ERROR (Status)) {
      StringBuffer = AllocatePool (AsciiStrSize (Lang) * sizeof (CHAR16));
      ASSERT (StringBuffer != NULL);
      AsciiStrToUnicodeStrS (Lang, StringBuffer, AsciiStrSize (Lang));
      }
      ASSERT (StringBuffer != NULL);
      gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
      FreePool (StringBuffer);
      OptionCount++;
    }
  }

  ASSERT (gLanguageToken != NULL);
  LangCode     = gLanguageString;
  OptionCount  = 0;
  if (Lang == NULL) {
    Lang = AllocatePool (AsciiStrSize (gLanguageString));
    ASSERT (Lang != NULL);
  }
  while (*LangCode != 0) {
    GetNextLanguage (&LangCode, Lang);
    if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
      if (AsciiStrCmp ("zh-CN", CurrentLang) == 0) {
        Flag = EFI_IFR_OPTION_DEFAULT;
    } else {
        Flag = 0;
    }
      HiiCreateOneOfOptionOpCode (
        OptionsOpCodeHandle,
        gLanguageToken[OptionCount],
        Flag,
        EFI_IFR_NUMERIC_SIZE_1,
        (UINT8) OptionCount
        );
      gCurrentLanguageIndex = (UINT8) OptionCount;
    } else {
      if (AsciiStrCmp ("en-US", CurrentLang) == 0) {
        Flag = EFI_IFR_OPTION_DEFAULT;
      } else {
        Flag = 0;
      }
      HiiCreateOneOfOptionOpCode (
        OptionsOpCodeHandle,
        gLanguageToken[OptionCount],
        Flag,
        EFI_IFR_NUMERIC_SIZE_1,
        (UINT8) OptionCount
        );
    }
    OptionCount++;
  }

  if (CurrentLang != NULL) {
    FreePool (CurrentLang);
  }
  FreePool (Lang);

  HiiCreateOneOfOpCode (
    StartOpCodeHandle,
    FRONT_PAGE_KEY_LANGUAGE,
    0,
    0,
    STRING_TOKEN(STR_LANGUAGE_PROMPT),
    STRING_TOKEN(STR_LANGUAGE_HELP),
    EFI_IFR_FLAG_CALLBACK,
    EFI_IFR_NUMERIC_SIZE_1,
    OptionsOpCodeHandle,
    NULL
    );  

  Status = HiiUpdateForm (
             HiiHandle,
             &mFormMainGuid,
             ROOT_FORM_ID,
             StartOpCodeHandle,
             EndOpCodeHandle
             );

  HiiFreeOpCodeHandle (StartOpCodeHandle);
  HiiFreeOpCodeHandle (EndOpCodeHandle);
  HiiFreeOpCodeHandle (OptionsOpCodeHandle);

}
//[-START-fc-ADD]//
EFI_STATUS
SetPBFLevel()
{
    //get PBF Information:
    ARM_SMC_ARGS              ArmSmcArgs;
    UINTN                     Level[8]={0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7};
    UINTN                     BufferSize;
    EFI_STATUS                Status;

    BufferSize = sizeof (SYSTEM_SETUP_CONFIGURATION);
    Status = HiiGetBrowserData(
               &gSystemConfigurationGuid,
               SETUP_VARIABLE_NAME,
               BufferSize,
               (UINT8 *)&(mSetupConfiguration)
               );
    if (EFI_ERROR (Status)) {
      return EFI_NOT_FOUND;
    }
    ArmSmcArgs.Arg0 = 0xC2000F06;//#define PHYTIUM_OEM_SVC_PBF_VERSION    0x82000001
    ArmSmcArgs.Arg1 = 0x00;
    ArmSmcArgs.Arg2 = Level[mSetupConfiguration.PBFLevel];
    DEBUG ((EFI_D_ERROR,"Get PBF level is :%lx\n",mSetupConfiguration.PBFLevel));
    ArmCallSmc (&ArmSmcArgs);
    DEBUG ((EFI_D_ERROR,"Get PBF level Arg0:%lx\n",ArmSmcArgs.Arg0));
    return EFI_SUCCESS; 
}
//[-END-fc-ADD]//
//[-START-fc-ADD]//
EFI_STATUS
GetPBFInfo(
    IN EFI_HII_HANDLE                    HiiHandle)
{
    //get PBF Information:
    ARM_SMC_ARGS              ArmSmcArgs;
    UINT16                    MajorVer;
    UINT16                    MinorVer;
    EFI_STRING                  StringPtr = NULL;
    UINTN                       NewLen = 10;

    ArmSmcArgs.Arg0 = 0x82000001;//#define PHYTIUM_OEM_SVC_PBF_VERSION    0x82000001
    ArmCallSmc (&ArmSmcArgs);
    // bit[16:31] Major version, BIT[0:15] Minor version
    DEBUG ((EFI_D_ERROR,"Get PBF version Arg0:%lx\n",ArmSmcArgs.Arg0));
    MajorVer = (UINT16)(ArmSmcArgs.Arg0 >> 16);
    MinorVer = (UINT16)(ArmSmcArgs.Arg0);

    StringPtr = AllocateZeroPool (NewLen);
    if (StringPtr == NULL)
    {
      return EFI_SUCCESS;
    }

    UnicodeSPrint (
      StringPtr, 
      NewLen, 
      L"%d.%d",
      MajorVer,MinorVer);

    HiiSetString(HiiHandle, STRING_TOKEN(STR_BOARD_CHIP_PBF_REV_VALUE),StringPtr, NULL);
    return EFI_SUCCESS;
}
//[-END-fc-ADD]//

/**
  Brief description of InitMainMenu.

  @param  HiiHandle

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
InitMainMenu (
  IN EFI_HII_HANDLE                         HiiHandle
  )
{
  EFI_STRING                      StringPtr;
  UINTN                           NewLen;
//add-klk-lyang-P000A-start//
  EFI_STATUS  Status;
  UINTN       LangSize;
  CHAR8       LangData[100];
//add-klk-lyang-P000A-end//
//add-klk-lyang-P000A-start//
  BIOS_ID_IMAGE*                  BiosIdPtr;

  BiosIdPtr = PcdGetPtr (PcdBiosIdImage);
//add-klk-lyang-P000A-end//

  NewLen = 100;

  StringPtr = AllocateZeroPool (NewLen);
  if (StringPtr == NULL) {
    return EFI_SUCCESS;
  }

//add-klk-lyang-P000A-start//
  Status =  gRT->GetVariable (L"PlatformLang", &gEfiGlobalVariableGuid, NULL, &LangSize, LangData);
  if (Status == EFI_NOT_FOUND) {
    Status = gRT->SetVariable (
                    L"PlatformLang",
                    &gEfiGlobalVariableGuid,
                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
                    AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang)),
                    (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang)
                    );
  }
//add-klk-lyang-P000A-end//
  UnicodeSPrint (
    StringPtr,
    NewLen, 
    L"UEFI %d.%d; PI %d.%d",
    ((UINT16*)&gST->Hdr.Revision)[1],
    ((UINT16*)&gST->Hdr.Revision)[0] / 10,
    ((UINT16*)&gDS->Hdr.Revision)[1],
    ((UINT16*)&gDS->Hdr.Revision)[0] / 10
  );
  HiiSetString(HiiHandle, STR_BIOS_COMPLIANCY_VALUE,StringPtr, NULL);

//add-fanchen-start//
  GetPBFInfo(HiiHandle);
//add-fanchen-end//
  //
  //BIOS GUID,It's a sample code.
  //
  ZeroMem(StringPtr, sizeof(StringPtr));
  //StrnCpy(StringPtr, L"80c75128-0b4c-4ccf-b9ab-afe75d8c21ee",23);//VERS.H
//add-klk-lyang-P000A-start//
  StrCpyS(StringPtr, NewLen, BiosIdPtr->BiosGuid);//VERS.H
//add-klk-lyang-P000A-end//
  InitString(HiiHandle, STRING_TOKEN(STR_BIOS_GUID_VALUE), L"%s", StringPtr);
  UpdateSetupPageStrings(HiiHandle);
//Language Menu
  UiCreateLanguageMenu(HiiHandle);
//add-klk-lyang-P000A-start//
//add-klk-lyang-P000A-end//
  if (StringPtr) {
    FreePool (StringPtr);
  }

  return EFI_SUCCESS;
}

/**
  Brief description of MainCallbackRoutine.

  @param  This
  @param  Action
  @param  QuestionId
  @param  Type
  @param  Value
  @param  ActionRequest

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
EFIAPI
MainCallbackRoutine (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
  IN  EFI_BROWSER_ACTION                     Action,
  IN  EFI_QUESTION_ID                        QuestionId,
  IN  UINT8                                  Type,
  IN  EFI_IFR_TYPE_VALUE                     *Value,
  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
  )
{
  EFI_STATUS                            Status; 
  //EFI_CALLBACK_INFO                     *CallbackInfo;
  //EFI_GUID                              VarStoreGuid = SYSTEM_CONFIGURATION_GUID;
  EFI_SMBIOS_TABLE_HEADER               *SmbiosRecord;
  UINTN                                 StrNum;

//[gliu-0009]
#if 0
  if (QuestionId != FRONT_PAGE_KEY_LANGUAGE) {
    //add-fanchen-start
    if (QuestionId != FORM_PBF_SET){
      return EFI_UNSUPPORTED;
    }
    //add-fanchen-end
  }
#endif
  if((QuestionId != FRONT_PAGE_KEY_LANGUAGE)  && (QuestionId != FORM_PBF_SET) && (QuestionId != FORM_MEMORY_FAST_TRAIN_SET)){
    return EFI_UNSUPPORTED;
  }
  if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
    if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) {
      Value->u8 = gCurrentLanguageIndex;
      Status = EFI_SUCCESS;
    } else {
      Status = EFI_UNSUPPORTED;
    }
    return Status;
  }
  if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
    Action  = EFI_BROWSER_ACTION_CHANGED;
    if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) {
      Value->u8 = 0;
    }
  }
  if (Action != EFI_BROWSER_ACTION_CHANGED) {
    return EFI_UNSUPPORTED;
  }
  *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
  //
  //The callback is called before/after setupbrowser, so need save/restore setup browser data to gSetupDataManagment SCBuffer
  //
  switch (QuestionId) {
  //add-fanchen-start
  case FORM_PBF_SET:
    DEBUG ((EFI_D_ERROR,"fanchen Get PBF level start LINE:%d\n",__LINE__));
    //SetPBFLevel();
    break;
  //add-fanchen-end 
  case FRONT_PAGE_KEY_LANGUAGE:
    LanguageChangeHandler(Value);
    gSmbiosHandle = (gSmbiosType < EFI_SMBIOS_TYPE_BIOS_LANGUAGE_INFORMATION) ? gSmbiosHandle : SMBIOS_HANDLE_PI_RESERVED;
    gSmbiosType = EFI_SMBIOS_TYPE_BIOS_LANGUAGE_INFORMATION;
    Status = gSmbiosProtocol->GetNext (gSmbiosProtocol, &gSmbiosHandle, &gSmbiosType, &SmbiosRecord, NULL);
    if (EFI_ERROR(Status)) {
      break;
    }
    StrNum = 1;
    if (Value->u8 == 0) {
      gSmbiosProtocol->UpdateString(gSmbiosProtocol, &gSmbiosHandle, &StrNum, "zhCN");
      StrNum = 2;
      gSmbiosProtocol->UpdateString(gSmbiosProtocol, &gSmbiosHandle, &StrNum, "enUS");
    } else {
      gSmbiosProtocol->UpdateString(gSmbiosProtocol, &gSmbiosHandle, &StrNum, "enUS");
      StrNum = 2;
      gSmbiosProtocol->UpdateString(gSmbiosProtocol, &gSmbiosHandle, &StrNum, "zhCN");
    }
//add-klk-lyang-P000A-end//
    break;
  default:
    break;
  }

  return EFI_SUCCESS;
}

/**
  Brief description of InstallMainCallbackRoutine.

  @param  DriverHandle
  @param  HiiHandle

  @retval EFI_SUCCESS   Function successful returned.
**/
EFI_STATUS
InstallMainCallbackRoutine (
  IN EFI_HANDLE                             DriverHandle,
  IN EFI_HII_HANDLE                         HiiHandle
  )
{

  EFI_STATUS                                Status;
  EFI_GUID                                  FormsetGuid = FORMSET_ID_GUID_MAIN;
  
  mMainCallBackInfo = AllocatePool (sizeof (EFI_CALLBACK_INFO));
  if (mMainCallBackInfo == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  mMainCallBackInfo->Signature                    = EFI_CALLBACK_INFO_SIGNATURE;
  mMainCallBackInfo->DriverCallback.ExtractConfig = GenericExtractConfig;
  mMainCallBackInfo->DriverCallback.RouteConfig   = GenericRouteConfig;
  mMainCallBackInfo->DriverCallback.Callback      = MainCallbackRoutine;
  mMainCallBackInfo->HiiHandle                    = HiiHandle;
  CopyGuid (&mMainCallBackInfo->FormsetGuid, &FormsetGuid);

  //
  // Install protocol interface
  //
  Status = gBS->InstallProtocolInterface (
                  &DriverHandle,
                  &gEfiHiiConfigAccessProtocolGuid,
                  EFI_NATIVE_INTERFACE,
                  &mMainCallBackInfo->DriverCallback
                  );
  Status = InitMainMenu(HiiHandle);
  return Status;
}
